package za.co.EYEWTKAH.jmsProjects.openJmsEmbedded;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.Options;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.derby.jdbc.EmbeddedDriver;

import com.btmatthews.utils.monitor.Logger;

public class StartJMS {

    private static String OPEN_JMS_HOME = "openjms.home";

    public static void main(String[] xargs) throws Exception {

        Options options = createOptions();

        CommandLineParser parser = new GnuParser();
        CommandLine cmd = parser.parse(options, xargs);

        String home = getHome(cmd.getOptionValue("h"));

        if(!new File(home).exists()){
            createJmsHome(home);
        }  
        
        System.setProperty(OPEN_JMS_HOME, home);
        String db_home = home + File.separator + "db";
        System.setProperty("derby.system.home", db_home);
        createDB(db_home);
        String configFileLocation = getConfigFileLocation(cmd.getOptionValue("c"));

        System.setProperty("java.security.policy", home + File.separator + "config" + File.separator + "openjms.policy");

        // org.exolab.jms.tools.db.DBTool.main(new String[] { "-recreate",
        // "-config", configFileLocation });

        String[] args = new String[] { "-config", configFileLocation };

        org.exolab.jms.server.JmsServer.main(args);

    }
    
    public static void startJMSServer(String openJmsHome, Boolean createHome, Logger logger) throws Exception{


        String home = getHome(openJmsHome);
        
        if(!new File(home).exists() && createHome){
            logger.logInfo("Creating OpenJMSHome is " + home);
            createJmsHome(home);
        }   
        
        System.setProperty(OPEN_JMS_HOME, home);
        String db_home = home + File.separator + "db";
        System.setProperty("derby.system.home", db_home);
        
        logger.logInfo("Creating db in " + db_home);
        createDB(db_home);
        String configFileLocation = openJmsHome + File.separator + "config/openjms.xml";
        
        if(createHome){
            logger.logInfo("Generating config");
            generateConfig("/openjms.xml",configFileLocation);    
        }

        System.setProperty("java.security.policy", home + File.separator + "config" + File.separator + "openjms.policy");
        String[] args = new String[] { "-config", configFileLocation };
        logger.logInfo("Starting server.");
        org.exolab.jms.server.JmsServer.main(args);
    
    }
    
    public static void stop(String openJmsHome, Boolean createHome, Logger logger) throws IOException{
    	String home = getHome(openJmsHome);
    	System.setProperty("java.security.policy", home + File.separator + "config" + File.separator + "openjms.policy");
    	String[] args = new String[] { "-stopServer"};
    	logger.logInfo("Shutting down open-jms");
    	org.exolab.jms.tools.admin.AdminMgr.main(args);
    }
    

    private static void generateConfig(String configLocation, String configFileLocation) throws FileNotFoundException, IOException {
        File file = new File(configFileLocation);
        FileUtils.deleteQuietly(file);
        InputStream is = StartJMS.class.getResourceAsStream(configLocation);        
        IOUtils.copy(is, new FileOutputStream(file));
    }

    private static void createDB(String db_home) throws Exception {
        String url = "jdbc:derby:openjms;create=true;upgrade=true";
        Class.forName(EmbeddedDriver.class.getName());
        Connection c = DriverManager.getConnection(url);

        String[] sqls = IOUtils.toString(StartJMS.class.getResourceAsStream("/jdbc-derby.sql")).split(";");
        for (int i = 0; i < sqls.length; i++) {
            String string = sqls[i];
            if (string == null || string.trim().startsWith("--") || string.trim().equals("")) {
                // ignoring
            } else {
                try {
                    c.prepareStatement(string).execute();    
                } catch (Exception e) {
                    if(!e.getMessage().contains("already exists")){
                        throw e;
                    }
                }
                
                
            }

        }
        c.commit();
        c.close();

        try {

            url = url + ";shutdown= true";
            c = DriverManager.getConnection(url);
            c.close();
        } catch (Exception e) {

        }

    }

    private static String getHome(String optionValue) throws IOException {
        if (optionValue == null) {

            String home = System.getProperty(OPEN_JMS_HOME);
            if (home != null) {
                return home;
            } else {

                String jmsHome = "target/openjmshome";                
                             
                return jmsHome;
            }

        } else {
            return optionValue;
        }

    }

    private static void createJmsHome(String jmsHome) throws IOException {
        InputStream is = StartJMS.class.getResourceAsStream("/za/co/openjms/config.zip");
        byte[] buffer = new byte[1024];
        ZipInputStream zis = new ZipInputStream(is);
        // get the zipped file list entry
        ZipEntry ze = zis.getNextEntry();

        while (ze != null) {

            String fileName = ze.getName();

            if (ze.isDirectory()) {
                File newFile = new File(jmsHome + File.separator + fileName);
                newFile.mkdir();
            } else {
                File newFile = new File(jmsHome + File.separator + fileName);
                //System.out.println("file unzip : " + newFile.getAbsoluteFile());

                // create all non exists folders
                // else you will hit FileNotFoundException for compressed folder
                new File(newFile.getParent()).mkdirs();

                FileOutputStream fos = new FileOutputStream(newFile);

                int len;
                while ((len = zis.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }

                fos.close();

            }

            ze = zis.getNextEntry();

        }

        zis.closeEntry();
        zis.close();

    }

    private static String getConfigFileLocation(String optionValue) {

        if (optionValue == null) {

            // String home = System.getProperty(OPEN_JMS_HOME);
            // return home + File.separator + "config/openjms.xml";
            return "src/main/resources/openjms.xml";
        }
        return optionValue;
    }

    private static Options createOptions() {

        Options options = new Options();

        options.addOption("c", "config", true, "the location of the config file");
        options.addOption("h", "open-jms-home", true, "open jms home directory");

        return options;
    }

}
